package com.demo.plugin;

import java.sql.Connection;
import java.util.Properties;

import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.RowBounds;

@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}))
public class MyBatisPagerPlugin implements Interceptor {
	private String dbType;

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		Object target = invocation.getTarget();
		if (target instanceof RoutingStatementHandler) {
			RoutingStatementHandler statementHandler = (RoutingStatementHandler)target;
			BoundSql boundSql = statementHandler.getBoundSql();
			MetaObject metaObject = MetaObject.forObject(statementHandler, 
					SystemMetaObject.DEFAULT_OBJECT_FACTORY,
					SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
					new DefaultReflectorFactory());
			RowBounds rowBounds = (RowBounds)metaObject.getValue("delegate.rowBounds");
			if (rowBounds != RowBounds.DEFAULT) {
				String sql = boundSql.getSql();
				StringBuffer pageSql = new StringBuffer(sql);
				if ("MYSQL".equalsIgnoreCase(dbType)) {
					pageSql.insert(0, "SELECT * FROM (");
					pageSql.append(") pager_mysql WHERE 1=1 LIMIT ");
					pageSql.append(rowBounds.getOffset());
					pageSql.append(",");
					pageSql.append(rowBounds.getLimit());
					metaObject.setValue("delegate.boundSql.sql", pageSql.toString());
				}else if ("ORACLE".equalsIgnoreCase(dbType)) {
					pageSql.insert(0, "SELECT * FROM (SELECT page_A.*, ROWNUM page_RN FROM (");
					pageSql.append(") page_A ");
					pageSql.append("WHERE ROWNUM <= ");
					pageSql.append(rowBounds.getOffset()+rowBounds.getLimit());
					pageSql.append(") WHERE page_RN >= ");
					pageSql.append(rowBounds.getOffset()+1);
				}
			}
		}
		return invocation.proceed();
	}

	@Override
	public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
	}

	@Override
	public void setProperties(Properties properties) {
		dbType = properties.getProperty("dbType");
	}

}
